# -*- coding: utf_8 -*-
# @Create   : 2021/9/24 9:03
# @Author   : yh
# @Remark   : 巡检记录Server层
import logging
import os
import time
from typing import List

from mxsoftpy import Server
from mxsoftpy.exception import DataError

from db.common.VideoManage.VideoQuality.conf import TestItemsDB, VideoDeviceDB
from db.common.VideoManage.VideoQuality.inspection_plan import InspectionPlanDB
from db.common.VideoManage.VideoQuality.inspection_record import InspectionRecordDB
from db.common.VideoManage.VideoQuality.inspection_task import InspectionTaskDB
from db.common.VideoManage.VideoQuality.video import VideoDB
from model.common.VideoManage.VideoQuality.inspection_record import InspectionRecordSelectModel
from utils.parser.fields import check_time_str
from utils.public.export_execl import ExportExecl, get_execl_headline
from utils.conf.mxconfig import MxConfig

from utils.public.params_method import update_select_params, get_pagination_params, paging_data, pro_null_value


class InspectionRecordServer(Server):
    __db__ = InspectionRecordDB

    def __init__(self):
        super().__init__()
        self.__plan_cache = dict()  # 巡检计划详情缓存
        self.__task_cache = dict()  # 巡检任务详情缓存
        self.__video_cache = dict()  # 视频详情缓存
        self.__device_type: dict = VideoDeviceDB('DeviceType').use_keys([])  # 所有设备类型字典

    def _export_data(self, data, test_name_dict):
        """
        转换成导出excl所需格式
        param: data 需要转换的列表
        param：test_name_dict 拼接headline
        """

        data_dict = {
            "header": "巡视记录",
            "headline": {
                "id": "序号",
                "device_name": "设备名称",
                "device_ip": "设备IP",
                **test_name_dict,
                "task_source": "任务来源",
                "principal": "负责人",
                "test_time": "检测时间",
            },
            "data": data
        }
        file_name = "record_" + str(int(time.time())) + ".xlsx"
        return data_dict, file_name

    def __select_plan_from_cache(self, plan_code: str) -> dict:
        """
        从缓存获取巡检计划详情（没有缓存就从数据库获取）
        :param plan_code: 要获取的计划code
        """
        if str(plan_code) == '0':
            return {'name': '临时任务'}
        elif self.__plan_cache.get(plan_code):
            return self.__plan_cache[plan_code]
        else:
            self.__plan_cache[plan_code] = InspectionPlanDB().retrieve(plan_code)
            return self.__plan_cache[plan_code]

    def __select_task_from_cache(self, task_code: str) -> dict:
        """
        从缓存获取巡检任务详情（没有缓存就从数据库获取）
        :param task_code: 要获取的任务code
        """
        if self.__task_cache.get(task_code):
            return self.__task_cache[task_code]
        else:
            self.__task_cache[task_code] = InspectionTaskDB().retrieve(task_code)
            return self.__task_cache[task_code]

    def __select_video_from_cache(self, video_code: str) -> dict:
        """
        从缓存获取视频详情（没有缓存就从数据库获取）
        :param video_code: 要获取的视频code
        """
        if self.__video_cache.get(video_code):
            return self.__video_cache[video_code]
        else:
            self.__video_cache[video_code] = VideoDB().retrieve(video_code)
            return self.__video_cache[video_code]

    @classmethod
    def tree_data(cls, record_data: List[dict]) -> dict:
        """
        按照task_code、video_code对数据进行分组
        :param record_data: 从数据库查询到的巡检记录
        :return: 分组后的数据
        """
        tree_data = dict()
        for i in record_data:  #
            if tree_data.get(i['task_code']):
                if tree_data[i['task_code']].get(i['video_code']):
                    tree_data[i['task_code']][i['video_code']][i['test_code']] = i['test_state']
                else:
                    tree_data[i['task_code']][i['video_code']] = dict()
                    tree_data[i['task_code']][i['video_code']][i['test_code']] = i['test_state']
            else:
                tree_data[i['task_code']] = dict()
                tree_data[i['task_code']][i['video_code']] = dict()
                tree_data[i['task_code']][i['video_code']][i['test_code']] = i['test_state']
        return tree_data

    def select(self, **select_model) -> dict:
        """
        查询巡检记录
        :param select_model: 查询及分页参数，查询参数字段见InspectionRecordSelectModel类
        """
        #  参数校验对空值进行处理
        export_code = select_model.get('export_code')
        select_model = pro_null_value(**select_model)
        select_data = InspectionRecordSelectModel(**select_model).dict()

        if isinstance(select_data['begin_time'], str):
            select_data['begin_time'] = check_time_str(select_data['begin_time'])
            select_data['end_time'] = check_time_str(select_data['end_time'])
        video_code = select_data['video_code']
        task_code = select_data['task_code']

        if video_code:       # 待修库跳转时根据video_code查询
            record_data = self.db.select(videos=[video_code])
            videos = VideoDB().simple_list(keys=[video_code])
            task_list = list(set([record['task_code'] for record in record_data]))
            tasks = InspectionTaskDB().simple_list(keys=task_list)

        elif task_code:      # 巡视任务跳转时根据task_code查询
            record_data = self.db.select(tasks=[task_code])
            tasks = InspectionTaskDB().simple_list(keys=[task_code])
            video_list = tasks[task_code]['videos'].split(";")
            videos = VideoDB().simple_list(keys=video_list)

        else:
            video_query = {
                'name__like': '*%s*' % select_data['device_name'],
                'device_ip__like': '*%s*' % select_data['device_ip']
            }
            videos = VideoDB().simple_list(is_all=True, **update_select_params(video_query))
            if not videos:
                raise DataError("未找到指定设备")
            task_query = {
                'begin_time__gte': select_data['begin_time'],
                'begin_time__lte': select_data['end_time'],
                'end_time__gte': select_data['begin_time'],
                'end_time__lte': select_data['end_time'],
                'name__like': '*%s*' % select_data['task_name'],
                'inspection_plan_code': select_data['plan_code'],
                'default_expression': '((0 and 1) or (2 and 3)) and 4 and 5'
            }
            tasks = InspectionTaskDB().simple_list(is_all=True, **update_select_params(task_query))
            if not tasks:
                raise DataError("未找到指定任务")
            record_data = self.db.select(videos.keys(), tasks, select_data)
        record_data.reverse()
        tree_data = self.tree_data(record_data)
        res_list = list()
        i = 0  # 序号
        test_items_dict = TestItemsDB('TestItems').list(['name'])
        for k, v in tree_data.items():
            task_items_dict = tasks[k]
            plan_items_dict = self.__select_plan_from_cache(task_items_dict['inspection_plan_code'])
            for x, y in v.items():
                i += 1
                video_items_dict = videos[x]

                res_dict = {'id': i,
                            'device_name': video_items_dict['name'],
                            'device_ip': video_items_dict['device_ip'],
                            'task_name': task_items_dict['name'],
                            'task_source': plan_items_dict['name'],
                            'device_type_name': self.__device_type.get(video_items_dict['device_type_code'])['name'],
                            'principal': task_items_dict['principal'],
                            'task_code': k,
                            'video_code': x,
                            'repair_state': video_items_dict['repair_state'],
                            'vendor': video_items_dict['vendor'],
                            'test_time': time.strftime("%Y-%m-%d %H:%M",
                                                       time.localtime(task_items_dict.get('end_time')))}

                if export_code == "1":  # 导出格式修改
                    for test_key in test_items_dict:
                        state_dict = {0: "未检测", 1: "正常", 2: "检测失败", 3: "故障"}
                        res_dict[test_items_dict[test_key]['name']] = state_dict.get(y.get(test_key)) or state_dict[0]

                else:
                    res_dict['test_data'] = [{'test_code': k,
                                              'test_state': y.get(k) or 0,
                                              'test_name': test_items_dict[k]['name']}
                                             for k, v in test_items_dict.items()]

                res_list.append(res_dict)

        if export_code == "1":  # 导出
            test_name_dict = get_execl_headline(test_items_dict)
            data_dict, file_name = self._export_data(res_list, test_name_dict)
            path = MxConfig.TMP_DIR + file_name
            execl_path = os.sep + "tmp" + os.sep + file_name

            if data_dict["data"]:
                try:
                    ExportExecl().data_process(data_dict)(path)
                    logging.info("成功导出excle")
                    return {'execl_path': execl_path}
                except DataError:
                    logging.error("导出excle出错")
                    raise DataError("导出excle出错")

            else:
                raise DataError("数据为空")

        return paging_data(res_list, **get_pagination_params(select_model))

